package com.simple.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.simple.common.constant.SystemRedisConstans;
import com.simple.common.exception.ServiceException;
import com.simple.common.utils.IpUtils;
import com.simple.framework.constant.HttpStatus;
import com.simple.framework.core.auth.JwtContext;
import com.simple.framework.core.domain.dto.ExportExcelDto;
import com.simple.framework.core.domain.vo.PagingVo;
import com.simple.framework.core.redis.RedisService;
import com.simple.framework.enums.ExportExcelWhere;
import com.simple.system.domain.dto.AddSysUserDto;
import com.simple.system.domain.dto.ListSysUserDto;
import com.simple.system.domain.dto.UpdateByLoginPasswordDto;
import com.simple.system.domain.dto.UpdateByLoginUserDto;
import com.simple.system.domain.entity.SysDept;
import com.simple.system.domain.entity.SysUser;
import com.simple.system.domain.vo.SysListUserSelectVo;
import com.simple.system.domain.vo.SysListUserVo;
import com.simple.system.domain.vo.SysUserDetailsVo;
import com.simple.system.mapper.SysDeptMapper;
import com.simple.system.mapper.SysPostMapper;
import com.simple.system.mapper.SysRoleMapper;
import com.simple.system.mapper.SysUserMapper;
import com.simple.system.service.SysUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * @Description 用户表(SysUser)表服务实现类
 * @Author xiaoke
 * @Date 2024/8/10 18:00
 * @Version 1.0
 */
@Service("sysUserService")
public class SysUserServiceImpl implements SysUserService {

    private final SysUserMapper sysUserMapper;

    private final SysRoleMapper sysRoleMapper;

    private final SysDeptMapper sysDeptMapper;

    private final SysPostMapper sysPostMapper;

    private final RedisService redisService;

    private final HttpServletRequest request;

    private final PasswordEncoder passwordEncoder;


    public SysUserServiceImpl(SysUserMapper sysUserMapper, SysRoleMapper sysRoleMapper, SysDeptMapper sysDeptMapper, SysPostMapper sysPostMapper, RedisService redisService, HttpServletRequest request, PasswordEncoder passwordEncoder) {
        this.sysUserMapper = sysUserMapper;
        this.sysRoleMapper = sysRoleMapper;
        this.sysDeptMapper = sysDeptMapper;
        this.sysPostMapper = sysPostMapper;
        this.redisService = redisService;
        this.request = request;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    public PagingVo<SysListUserVo> list(ListSysUserDto dto) {
        dto.setPageNum((dto.getPageNum() - 1) * dto.getPageSize());
        List<SysListUserVo> sysListUserVos = sysUserMapper.listUser(dto);
        return new PagingVo<>(sysListUserVos, sysUserMapper.listUserTotal(dto));
    }

    @Override
    public List<String> getUserPerms(Long userId) {
        return sysUserMapper.getUserPerms(userId);
    }

    @Override
    public SysUserDetailsVo getUserDetails(Long userId) {
        return sysUserMapper.getUserDetails(userId);
    }

    @Override
    public SysUserDetailsVo getUserNameDetails(String username) {
        return sysUserMapper.getUserNameDetails(username);
    }

    @Override
    @Transactional
    public void delete(Long id) {
        if (sysDeptMapper.checkUserUse(id) > 0) {
            throw new ServiceException("该用户已分配给部门，无法删除", HttpStatus.BAD_REQUEST);
        }
        sysUserMapper.deleteById(id);
        sysUserMapper.deleteByIdRole(id);
    }

    @Override
    public SysUserDetailsVo getByCellphone(String cellphone) {
        return sysUserMapper.getUserPhoneDetails(cellphone);
    }


    @Override
    public List<SysListUserSelectVo> listSelect() {
        List<SysListUserSelectVo> list = redisService.getCacheList(SystemRedisConstans.SYS_USER_SELECT_LIST);
        if (list != null && !list.isEmpty()) {
            return list;
        }
        list = sysUserMapper.listSelect();
        redisService.setCacheList(SystemRedisConstans.SYS_USER_SELECT_LIST, list);
        return list;
    }

    @Override
    public void updateByLogin(SysUser sysUser) {
        sysUserMapper.updateById(sysUser);
    }

    @Transactional
    @Override
    public Long create(AddSysUserDto dto) {
        checkRoleIds(dto.getRoleIds());
        checkPostIds(dto.getPostIds());
        checkDeptId(dto.getDeptId());
        if (sysUserMapper.existUserName(dto.getUsername()) != null) {
            throw new ServiceException("该用户名不可用", HttpStatus.BAD_REQUEST);
        }
        if (sysUserMapper.existUserPhone(dto.getPhone()) > 0) {
            throw new ServiceException("该手机号码不可用", HttpStatus.BAD_REQUEST);
        }
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(dto, sysUser);
        sysUser.setCreatorId(JwtContext.getUserId());
        sysUserMapper.insert(sysUser);
        sysUserMapper.deleteByIdRole(sysUser.getId());
        //新增用户角色
        if (dto.getRoleIds() != null && !dto.getRoleIds().isEmpty()) {
            sysUserMapper.insertUserRole(dto.getRoleIds(), sysUser.getId());
        }
        //新增用户岗位
        setUserPost(dto.getPostIds(), sysUser.getId());
        return sysUser.getId();
    }

    @Transactional
    @Override
    public void update(Long id, AddSysUserDto dto) {
        checkRoleIds(dto.getRoleIds());
        checkPostIds(dto.getPostIds());
        checkDeptId(dto.getDeptId());
        SysUser sysUser = sysUserMapper.selectById(id);
        if (sysUser == null) {
            throw new ServiceException("用户不存在", HttpStatus.BAD_REQUEST);
        }
        BeanUtils.copyProperties(dto, sysUser);
        SysUser tmpUser = sysUserMapper.existUserName(dto.getUsername());
        if (tmpUser != null && !tmpUser.getId().equals(id)) {
            throw new ServiceException("该用户名不可用", HttpStatus.BAD_REQUEST);
        }
        sysUserMapper.updateById(sysUser);
        setUserRole(dto.getRoleIds(), id);
        setUserPost(dto.getPostIds(), id);
    }

    @Override
    public void updateByLoginUser(UpdateByLoginUserDto dto) {
        SysUser sysUser = sysUserMapper.selectById(JwtContext.getUserId());
        if (sysUser == null) {
            throw new ServiceException("用户不存在");
        }
        BeanUtils.copyProperties(dto, sysUser);
        sysUserMapper.updateById(sysUser);
    }

    @Override
    public void updateByLoginPassword(UpdateByLoginPasswordDto dto) {
        if (!dto.getNewPassword().equals(dto.getConfirmPassword())) {
            throw new ServiceException("新密码与确认密码不一致", HttpStatus.BAD_REQUEST);
        }
        SysUser sysUser = sysUserMapper.selectById(JwtContext.getUserId());
        sysUser.setPassword(passwordEncoder.encode(dto.getNewPassword()));
        sysUserMapper.updateById(sysUser);
    }


    /**
     * 检查权限角色Id集合是否合格
     *
     * @param ids 角色集合
     */
    private void checkRoleIds(Set<Long> ids) {
        if (ids == null || ids.isEmpty()) return;
        Integer num = sysRoleMapper.existRoles(ids);
        if (num != ids.size()) {
            throw new ServiceException("角色集合存在不合格Id", HttpStatus.BAD_REQUEST);
        }
    }

    /**
     * 检查权限岗位Id集合是否合格
     *
     * @param ids 岗位集合
     */
    private void checkPostIds(Set<Long> ids) {
        Integer num = sysPostMapper.existPosts(ids);
        if (num != ids.size()) {
            throw new ServiceException("岗位集合存在不合格Id", HttpStatus.BAD_REQUEST);
        }
    }

    /**
     * 检查部门Id是否正确
     *
     * @param id 部门Id
     */
    private void checkDeptId(Long id) {
        SysDept sysDept = sysDeptMapper.selectById(id);
        if (sysDept == null) {
            throw new ServiceException("部门不存在", HttpStatus.BAD_REQUEST);
        }
    }

    /**
     * 设置用户角色
     *
     * @param ids 权限集合
     * @param id  角色Id
     */
    private void setUserRole(Set<Long> ids, Long id) {
        if (ids == null || ids.isEmpty()) return;
        sysUserMapper.deleteByIdRole(id);
        sysUserMapper.insertUserRole(ids, id);
    }

    /**
     * 设置用户岗位
     *
     * @param ids 权限集合
     * @param id  岗位Id
     */
    private void setUserPost(Set<Long> ids, Long id) {
        sysPostMapper.deleteByIdPost(id);
        sysPostMapper.insertUserPost(ids, id);
    }

    /**
     * 更新用户id城市
     *
     * @param id 用户id
     */
    @Override
    public void updateIpCityById(Long id) {
        String ipAddr = IpUtils.getIpAddr(request);
        String[] strings = IpUtils.parseIpAddr(ipAddr);
        SysUser sysUser = new SysUser();
        sysUser.setId(id);
        sysUser.setIpCity(strings[0].equals("0") ? "未知" : strings[0]);
        sysUserMapper.updateById(sysUser);
    }

    @Override
    public boolean checkDeptByUser(Long deptId) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getDeptId, deptId);
        return sysUserMapper.selectCount(queryWrapper) > 0;
    }

    @Override
    public List<SysListUserVo> export(ExportExcelDto<ListSysUserDto> dto) {
        List<SysListUserVo> list = new ArrayList<>();
        //条件导出
        if (dto.getWhere().equals(ExportExcelWhere.QUERY.getValue())) {
            list = list(dto.getQueryParams()).getRows();
        }
        //选择导出
        if (dto.getWhere().equals(ExportExcelWhere.SELECT.getValue())) {
            if (dto.getSelectedRowKeys().isEmpty()) {
                throw new ServiceException("请选择要导出的数据");
            }
            list = sysUserMapper.listByIds(dto.getSelectedRowKeys());
        }
        //全部导出
        if (dto.getWhere().equals(ExportExcelWhere.ALL.getValue())) {
            list = sysUserMapper.listAll();
        }
        if (list.isEmpty()) {
            throw new ServiceException("没有数据可导出");
        }
        return list;
    }
}

